/********************************************************************************************
 Class Name: NMRLeadRoundRobin
 Author: Accenture
 Date: 2/29/2012
 Requirement/Project Name: NMR
 Requirement Description: Class for Reassignment of Leads with round robin logic
 Version History:
 ***********************************************************************************************/
public class NMRLeadRoundRobin{

    Public static Map<String,Channel_and_Office_Assignment__c> mCOgroupId = new Map<String,Channel_and_Office_Assignment__c>();
    //inner class to hold list of group members against an integer for calculation of round robin
    class userInfoClass
    {
        List<Assignment_Groups__c> lag;
        Integer idx;
    }
    //Assigns the Leads to the group members (Users) from the specific Assignment groups according to Zip Code
    public static void executeRoundRobin(List<Lead> leadsList ,Map <ID, Lead> LeadIdMap,Set<String> ZipStr)
    {
        
        Set<Id> sGroupIds = new Set<Id>();
        Set<Id> queueIds = new Set<Id>();
        Set<Id> qrIds= new Set<Id>();

        List<Assignment_Groups__c> lagroup = new List<Assignment_Groups__c>();
        List<Lead> qrList = new List<Lead>();//for Updating selected leads according to lead Zipcode
        List<Lead> marketgroupLeads = new List<Lead>();
        List<Assignment_Groups__c> lAG = null;                                                                         
        List<Assignment_Group_Name__c> assignmentGroup = null;                                                               
        List<Lead> updateqrList = new List<Lead>();
        // Stores the Assignment_Group_Name__c into the map assignmentGroupMap  
        Map<ID, Assignment_Group_Name__c> assignmentGroupMap  = new Map<ID, Assignment_Group_Name__c> ();
        Map<String, userInfoClass> mGroupMember = new Map<String,userInfoClass>();
        // Stores the Assignment_Groups__c into the map mUpdateAG 
        Map<Id, Assignment_Groups__c> mUpdateAG = new Map<Id, Assignment_Groups__c>();
       // Maps the queue ID with Assignment group
        Map<String, ID> mAGgroupId = getmapAssignmentId(ZipStr);
        Set<String> ZipList = new Set<String>();
        for(Lead  c : leadsList)
        {    
            
            
                //find the assignment group
                 
                if(mAGgroupId.containsKey(c.PostalCode+c.LeadSource+c.Lead_Type__c) && mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Lead_Source__c == c.LeadSource && mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Lead_Type__c == c.Lead_Type__c)
                {
                  if(c.Weight_Check_from_heading__c == True && c.Lead_Type__c == 'Listing Creation'){
                        if(mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Heading_Weight_Max__c == 1 && mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Lead_Type__c == 'Listing Creation'){
                            Id gId = mAGgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c);
                            sGroupIds.add(gId);
                            ZipList.add(c.PostalCode+c.LeadSource+c.Lead_Type__c);
                            qrList.add(c);
                            qrIds.add(c.Id);
                        }
                        else{
                            marketgroupLeads.add(c);
                        }
                    }
                    else{                   
                    Id gId = mAGgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c);
                    sGroupIds.add(gId);
                    //queueIds.add(c.OwnerId);
                    ZipList.add(c.PostalCode+c.LeadSource+c.Lead_Type__c);
                    qrList.add(c);
                    qrIds.add(c.Id);
                    system.debug('Inside mAGgroupId'+qrIds+mAGgroupId);
                    }
                }
                //To assign the lead to a marketing queue
                else{
                    
                    marketgroupLeads.add(c);
                }
            
        }
        //Market group addition
     /**   if(marketgroupLeads.size()>0){
            Queuesobject nmrQueue = [select QueueId, Queue.Name from Queuesobject where Queue.name = : 'Marketing'];
            for(Lead marketlead:marketgroupLeads){
                marketlead.ownerId = nmrQueue.QueueId;
            }
            
        }**/
        if(!qrIds.isEmpty())
        {
            //qrList = getOwnerIDOfLeads(qrIds);
            lAG = getAssignmentGroupsMembers(sGroupIds);                                                                         
            assignmentGroup = getAssignmentGroup(sGroupIds);
            system.debug('WWWWW'+lAG);                                                               
            for(Assignment_Group_Name__c obj : assignmentGroup )
            {    
               assignmentGroupMap.put(obj.id, obj ) ;
            }                                                                 
            for(Id gId : sGroupIds)
            {
                for(Assignment_Groups__c ag : lAG)
                {
                    if(ag.Group_Name__c == gId)
                    {
                        lagroup.add(ag);
                    }  
                }
                if(!lagroup.isEmpty())
                {   
                    userInfoClass u = new userInfoClass();
                    u.lag = lagroup;
                    u.idx = 0;
                    for(String Str: ZipList)
                    {   
                        if(mAGgroupId.get(Str) == gId)
                        {   
                            mGroupMember.put(Str,u);
                        }
                    }
                }
            }
        
            for(Lead c : qrList)
            {        
                //system.debug('#############'+mGroupMember+'#######'+qrList);
                if(mGroupMember.containsKey(c.PostalCode+c.LeadSource+c.Lead_Type__c))
                {
                    system.debug('**************'+mGroupMember.get(c.PostalCode+c.LeadSource+c.Lead_Type__c));
                    userInfoClass u_item = mGroupMember.get(c.PostalCode+c.LeadSource+c.Lead_Type__c);
                    Assignment_Groups__c ag_item = u_item.lag[u_item.idx];
                    Assignment_Group_Name__c assignGroupObj  = assignmentGroupMap.get(ag_item.Group_Name__c);
                    
                    //Check the assignment group is part of round robin
                    if(assignGroupObj!= null && assignGroupObj.Round_Robin__c)
                    {
                        //Added for office , channel and assignment group to lead
                        LeadIdMap.get(c.Id).NMR_Sales_Rep__c = ag_item.User__c;
                        LeadIdMap.get(c.Id).OwnerId = ag_item.Manager__c;
                        LeadIdMap.get(c.Id).NMR_Office__c = mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Office_Name__c;
                        LeadIdMap.get(c.Id).Channel__c = mCOgroupId.get(c.PostalCode+c.LeadSource+c.Lead_Type__c).Channel_Name__c;
                        LeadIdMap.get(c.Id).Assignment_Group__c = ag_item.Group_Name__c;
                        //system.debug('@@@@@@@@@@@@@@@@'+c.OwnerId);
                        updateqrList.add(c); // add into case update list
                    }
                    //Check if  assignment goroup is associated with the queue and is  part of round robin
                    if(!mUpdateAG.containsKey(ag_item.Id) && assignGroupObj!= null && assignGroupObj.Round_Robin__c)
                    {
                        datetime now = datetime.now();
                        ag_item.Last_Assignment__c = now;
                        ag_item.Millisecond__c = now.millisecondGMT();
                        mUpdateAG.put(ag_item.Id, ag_item);
                    }
                 
                    u_item.idx++;
                    u_item.idx = math.mod(u_item.idx, u_item.lag.size());
                }
                else{
                    marketgroupLeads.add(c);
                }
            }
       
            try 
            {
               if(marketgroupLeads.size() > 0)
                {
                    Queuesobject nmrQueue = [select QueueId, Queue.Name from Queuesobject where Queue.name = : 'Marketing'];
                    for(Lead marketlead:marketgroupLeads){
                        marketlead.ownerId = nmrQueue.QueueId;
                    }
                    
                }
                if(mUpdateAG.values().size() >0)
                {
                    update mUpdateAG.values(); // update Assignment Time for Assignment Group Member
                    
                }
                
            }
            catch (Exception ex)
            {
                //GeneralConstants.mailAnyExceptionToMe('NMRLeadRoundRobin','executeRoundRobin',ex);
                System.debug('Exception in update the Lead and Assignment Group Member: ' + ex);
            }
        }
        
    }
    public static List<Lead> getOwnerIDOfLeads( Set<Id> qrIds)
    {
        return [select Id,OwnerId,PostalCode from Lead where Id IN: qrIds];   
    }
    /*
     *  Returns the users of the Assignment group
     *
     **/
    public static List<Assignment_Groups__c> getAssignmentGroupsMembers( Set<Id> sGroupIds)
    {
        
        return [select a.Id, a.Name, a.Group_Name__c, a.User__c, a.Manager__c from Assignment_Groups__c a
                                                                         where  a.Active__c =: 'true' 
                                                                         and a.User_Active__c =: 'true' 
                                                                      
                                                                         and a.Group_Name__c IN: sGroupIds                                                                         
                                                                         ORDER BY Last_Assignment__c,Millisecond__c ASC];
        
    } 
     /*
     *  Returns  the Assignment group
     *
     **/  
    public static List<Assignment_Group_Name__c> getAssignmentGroup(Set<Id> sGroupIds)
    {
       return [Select Id ,a.Name,a.Office_Code__c, a.OwnerId, a.Round_Robin__c from Assignment_Group_Name__c a where id in :sGroupIds];                                                                  
    }
    
    /*
     *  Returns  Office associated the Assignment group
     *
     **/  
    
    public static Map<String, ID> getmapAssignmentId(Set<string> ZipStr){
        
        
        Map<String, ID> mAGQIdbyZip = null;
        if(mAGQIdbyZip == null){
            mAGQIdbyZip = new Map<String, ID>();
            
            for(Channel_and_Office_Assignment__c g : [select a.Name,a.Office_Name__c, a.Channel_Name__c, a.Id,a.Heading_Weight_Max__c,a.Zip_Code__c,a.Lead_Source__c,a.Lead_Type__c,a.Assignment_Group__c  
                                                from Channel_and_Office_Assignment__c a 
                                                where a.Active__c  =: true AND a.Zip_Code__c IN:ZipStr]){
                mAGQIdbyZip.put(g.Zip_Code__c+g.Lead_Source__c+g.Lead_Type__c, g.Assignment_Group__c);   
                mCOgroupId.put(g.Zip_Code__c+g.Lead_Source__c+g.Lead_Type__c,g);   
            }
           
        }      
        return mAGQIdbyZip;
    }
}